package com.zcbl.toolkit.aliyun.oss;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.model.PutObjectResult;
import com.zcbl.toolkit.exception.SystemRuntimeException;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.util.Assert;

import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author he peng
 * @create 2018/4/26 13:21
 * @see
 */
public class DefaultOSSEnhanceClient extends OSSClient implements OSSEnhance , InvocationHandler {

    private OSSClient ossClient;
    private OSSProperties ossProperties;

    public DefaultOSSEnhanceClient(String endpoint, CredentialsProvider credsProvider,
                                   ClientConfiguration config , OSSProperties ossProperties ,
                                   OSSClient ossClient) {
        super(endpoint, credsProvider, config);
        this.ossProperties = ossProperties;
        this.ossClient = ossClient;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            return method.invoke(this, args);
        } catch (Exception e) {
            throw new SystemRuntimeException("aliyun OSS Error ", e);
        }
    }

    @Override
    public Map<String, PutObjectPathResultWrapper> putObject(String bucketName, Map<String, InputStream> inputMap) {
        Assert.hasLength(bucketName , "bucketName Length == 0");
        if (CollectionUtils.sizeIsEmpty(inputMap)) {
            return new HashMap<>(0);
        }
        HashMap<String, PutObjectPathResultWrapper> putResultMap = new HashMap<>(inputMap.size());
        inputMap.entrySet().stream().forEach(entry -> {
            PutObjectResult putObjectResult = this.ossClient.putObject(bucketName, entry.getKey(), entry.getValue());
            PutObjectPathResultWrapper wrapper = PutObjectPathResultWrapper.builder()
                    .putObjectResult(putObjectResult)
                    .objectUrl(getObjectExternalUrl(entry.getKey(), this.ossProperties))
                    .build();
            putResultMap.put(entry.getKey() , wrapper);
        });
        return putResultMap;
    }

    @Override
    public Map<String, PutObjectPathResultWrapper> putObject(Map<String, InputStream> inputMap) {
        if (CollectionUtils.sizeIsEmpty(inputMap)) {
            return new HashMap<>(0);
        }
        HashMap<String, PutObjectPathResultWrapper> putResultMap = new HashMap<>(inputMap.size());
        inputMap.entrySet().stream().forEach(entry -> {
            PutObjectResult putObjectResult =
                    this.ossClient.putObject(this.ossProperties.getBucket() , entry.getKey(), entry.getValue());
            PutObjectPathResultWrapper wrapper = PutObjectPathResultWrapper.builder()
                    .putObjectResult(putObjectResult)
                    .objectUrl(getObjectExternalUrl(entry.getKey(), this.ossProperties))
                    .build();
            putResultMap.put(entry.getKey() , wrapper);
        });
        return putResultMap;
    }

    @Override
    public PutObjectPathResultWrapper putObject(String key , InputStream inputStream) {
        Assert.hasLength(key , "key Length == 0");
        Assert.notNull(inputStream , "inputStream == null");
        PutObjectResult putObjectResult = this.ossClient.putObject(this.ossProperties.getBucket() , key , inputStream);
        PutObjectPathResultWrapper wrapper = PutObjectPathResultWrapper.builder()
                .putObjectResult(putObjectResult)
                .objectUrl(getObjectExternalUrl(key , this.ossProperties))
                .build();
        return wrapper;
    }

    @Override
    public String getObjectExternalUrl(String key, OSSProperties ossProperties) {
        Assert.hasLength(key , "key Length == 0");
        Assert.notNull(ossProperties , "ossProperties == null");
        return new StringBuilder(ossProperties.getProtocol())
                .append(ossProperties.getBucket())
                .append(".")
                .append(ossProperties.getExternalEndpoint())
                .append("/")
                .append(key).toString();
    }

    @Override
    public String getObjectExternalUrl(String key) {
        Assert.hasLength(key , "key Length == 0");
        return new StringBuilder(this.ossProperties.getProtocol())
                .append(this.ossProperties.getBucket())
                .append(".")
                .append(this.ossProperties.getExternalEndpoint())
                .append("/")
                .append(key).toString();
    }

    @Override
    public String getObjectExternalUrl(String bucket, String key, OSSProperties ossProperties) {
        Assert.hasLength(key , "key Length == 0");
        Assert.notNull(ossProperties , "ossProperties == null");
        return new StringBuilder(ossProperties.getProtocol())
                .append(bucket)
                .append(".")
                .append(ossProperties.getExternalEndpoint())
                .append("/")
                .append(key).toString();
    }

    @Override
    public String getObjectInternalUrl(String key, OSSProperties ossProperties) {
        Assert.hasLength(key , "key Length == 0");
        Assert.notNull(ossProperties , "ossProperties == null");
        return new StringBuilder(ossProperties.getProtocol())
                .append(ossProperties.getBucket())
                .append(".")
                .append(ossProperties.getInternalEndpoint())
                .append("/")
                .append(key).toString();
    }

    @Override
    public String getObjectInternalUrl(String key) {
        Assert.hasLength(key , "key Length == 0");
        return new StringBuilder(this.ossProperties.getProtocol())
                .append(this.ossProperties.getBucket())
                .append(".")
                .append(this.ossProperties.getInternalEndpoint())
                .append("/")
                .append(key).toString();
    }

    @Override
    public String getObjectInternalUrl(String bucket, String key, OSSProperties ossProperties) {
        Assert.hasLength(key , "key Length == 0");
        Assert.notNull(ossProperties , "ossProperties == null");
        return new StringBuilder(ossProperties.getProtocol())
                .append(bucket)
                .append(".")
                .append(ossProperties.getInternalEndpoint())
                .append("/")
                .append(key).toString();
    }
}
